// frontend/utils/resource-loader.js
/**
 * 资源加载优化工具 🚀
 * 
 * 提供前端资源加载优化功能，包括预加载、懒加载、资源优先级管理等
 */

/**
 * 资源加载器类
 */
class ResourceLoader {
  /**
   * 初始化资源加载器
   * @param {Object} options - 配置选项
   */
  constructor(options = {}) {
    this.options = {
      preloadImages: true,
      preloadFonts: true,
      lazyLoadThreshold: 0.1,
      priorityTimeout: 2000,
      ...options
    };
    
    this.resourceQueue = [];
    this.loadedResources = new Set();
    this.observers = new Map();
    this.priorityTimer = null;
    
    // 初始化
    this.init();
  }
  
  /**
   * 初始化
   */
  init() {
    // 检查浏览器支持
    this.supportsIntersectionObserver = 'IntersectionObserver' in window;
    this.supportsPreload = 'relList' in document.createElement('link') && 
                          document.createElement('link').relList.supports('preload');
    
    // 创建交叉观察器
    if (this.supportsIntersectionObserver) {
      this.createObserver();
    }
    
    // 监听页面加载完成事件
    window.addEventListener('load', () => {
      // 延迟加载非关键资源
      setTimeout(() => this.loadDeferredResources(), 1000);
    });
  }
  
  /**
   * 创建交叉观察器
   */
  createObserver() {
    this.observer = new IntersectionObserver(entries => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const element = entry.target;
          const resourceId = element.dataset.resourceId;
          
          if (resourceId && this.observers.has(resourceId)) {
            const resource = this.observers.get(resourceId);
            this.loadResource(resource);
            this.observers.delete(resourceId);
            this.observer.unobserve(element);
          }
        }
      });
    }, {
      threshold: this.options.lazyLoadThreshold,
      rootMargin: '200px'
    });
  }
  
  /**
   * 预加载关键资源
   * @param {Array} resources - 资源列表
   */
  preloadCriticalResources(resources) {
    if (!Array.isArray(resources) || resources.length === 0) return;
    
    resources.forEach(resource => {
      resource.priority = 'critical';
      this.queueResource(resource);
    });
    
    // 立即加载关键资源
    this.processQueue();
  }
  
  /**
   * 预加载图片
   * @param {Array} images - 图片URL列表
   */
  preloadImages(images) {
    if (!this.options.preloadImages || !Array.isArray(images) || images.length === 0) return;
    
    images.forEach(src => {
      this.queueResource({
        type: 'image',
        src,
        priority: 'high'
      });
    });
    
    // 处理队列
    this.processQueue();
  }
  
  /**
   * 预加载字体
   * @param {Array} fonts - 字体列表
   */
  preloadFonts(fonts) {
    if (!this.options.preloadFonts || !Array.isArray(fonts) || fonts.length === 0) return;
    
    fonts.forEach(font => {
      this.queueResource({
        type: 'font',
        src: font.src,
        family: font.family,
        priority: 'high'
      });
    });
    
    // 处理队列
    this.processQueue();
  }
  
  /**
   * 懒加载资源
   * @param {Object} resource - 资源对象
   * @param {HTMLElement} element - 触发元素
   */
  lazyLoad(resource, element) {
    if (!resource || !element) return;
    
    // 生成资源ID
    const resourceId = `${resource.type}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    // 存储资源
    this.observers.set(resourceId, resource);
    
    // 设置元素属性
    element.dataset.resourceId = resourceId;
    
    // 观察元素
    if (this.supportsIntersectionObserver) {
      this.observer.observe(element);
    } else {
      // 回退方案：延迟加载
      setTimeout(() => this.loadResource(resource), 2000);
    }
  }
  
  /**
   * 将资源添加到队列
   * @param {Object} resource - 资源对象
   */
  queueResource(resource) {
    if (!resource || !resource.src) return;
    
    // 检查是否已加载
    const resourceKey = `${resource.type}-${resource.src}`;
    if (this.loadedResources.has(resourceKey)) return;
    
    // 添加到队列
    this.resourceQueue.push({
      ...resource,
      key: resourceKey,
      status: 'queued'
    });
    
    // 按优先级排序队列
    this.sortQueue();
  }
  
  /**
   * 按优先级排序队列
   */
  sortQueue() {
    const priorityMap = {
      'critical': 0,
      'high': 1,
      'medium': 2,
      'low': 3
    };
    
    this.resourceQueue.sort((a, b) => {
      const priorityA = priorityMap[a.priority] || 999;
      const priorityB = priorityMap[b.priority] || 999;
      return priorityA - priorityB;
    });
  }
  
  /**
   * 处理队列
   */
  processQueue() {
    // 清除之前的定时器
    if (this.priorityTimer) {
      clearTimeout(this.priorityTimer);
    }
    
    // 处理关键和高优先级资源
    const highPriorityResources = this.resourceQueue.filter(
      resource => resource.priority === 'critical' || resource.priority === 'high'
    );
    
    highPriorityResources.forEach(resource => {
      this.loadResource(resource);
    });
    
    // 设置定时器处理中优先级资源
    this.priorityTimer = setTimeout(() => {
      const mediumPriorityResources = this.resourceQueue.filter(
        resource => resource.priority === 'medium' && resource.status === 'queued'
      );
      
      mediumPriorityResources.forEach(resource => {
        this.loadResource(resource);
      });
      
      // 再次设置定时器处理低优先级资源
      this.priorityTimer = setTimeout(() => {
        const lowPriorityResources = this.resourceQueue.filter(
          resource => resource.priority === 'low' && resource.status === 'queued'
        );
        
        lowPriorityResources.forEach(resource => {
          this.loadResource(resource);
        });
      }, this.options.priorityTimeout);
    }, this.options.priorityTimeout);
  }
  
  /**
   * 加载资源
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadResource(resource) {
    if (!resource || !resource.src) return Promise.reject(new Error('Invalid resource'));
    
    // 更新状态
    resource.status = 'loading';
    
    // 根据资源类型加载
    switch (resource.type) {
      case 'image':
        return this.loadImage(resource);
      case 'font':
        return this.loadFont(resource);
      case 'script':
        return this.loadScript(resource);
      case 'style':
        return this.loadStyle(resource);
      default:
        return this.loadGeneric(resource);
    }
  }
  
  /**
   * 加载图片
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadImage(resource) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      
      img.onload = () => {
        this.resourceLoaded(resource);
        resolve(img);
      };
      
      img.onerror = (error) => {
        this.resourceFailed(resource, error);
        reject(error);
      };
      
      img.src = resource.src;
    });
  }
  
  /**
   * 加载字体
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadFont(resource) {
    return new Promise((resolve, reject) => {
      if (!resource.family) {
        this.resourceFailed(resource, new Error('Font family not specified'));
        return reject(new Error('Font family not specified'));
      }
      
      const fontFace = new FontFace(resource.family, `url(${resource.src})`);
      
      fontFace.load()
        .then(loadedFace => {
          document.fonts.add(loadedFace);
          this.resourceLoaded(resource);
          resolve(loadedFace);
        })
        .catch(error => {
          this.resourceFailed(resource, error);
          reject(error);
        });
    });
  }
  
  /**
   * 加载脚本
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadScript(resource) {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      
      script.onload = () => {
        this.resourceLoaded(resource);
        resolve(script);
      };
      
      script.onerror = (error) => {
        this.resourceFailed(resource, error);
        reject(error);
      };
      
      script.async = resource.async !== false;
      script.defer = resource.defer !== false;
      script.src = resource.src;
      
      document.head.appendChild(script);
    });
  }
  
  /**
   * 加载样式
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadStyle(resource) {
    return new Promise((resolve, reject) => {
      const link = document.createElement('link');
      
      link.onload = () => {
        this.resourceLoaded(resource);
        resolve(link);
      };
      
      link.onerror = (error) => {
        this.resourceFailed(resource, error);
        reject(error);
      };
      
      link.rel = 'stylesheet';
      link.href = resource.src;
      
      document.head.appendChild(link);
    });
  }
  
  /**
   * 加载通用资源
   * @param {Object} resource - 资源对象
   * @returns {Promise} 加载Promise
   */
  loadGeneric(resource) {
    return new Promise((resolve, reject) => {
      if (!this.supportsPreload) {
        // 不支持预加载，直接标记为已加载
        this.resourceLoaded(resource);
        return resolve();
      }
      
      const link = document.createElement('link');
      
      link.onload = () => {
        this.resourceLoaded(resource);
        resolve(link);
      };
      
      link.onerror = (error) => {
        this.resourceFailed(resource, error);
        reject(error);
      };
      
      link.rel = 'preload';
      link.href = resource.src;
      
      // 设置as属性
      if (resource.as) {
        link.setAttribute('as', resource.as);
      } else {
        // 根据URL猜测资源类型
        const extension = resource.src.split('.').pop().toLowerCase();
        switch (extension) {
          case 'jpg':
          case 'jpeg':
          case 'png':
          case 'gif':
          case 'webp':
          case 'svg':
            link.setAttribute('as', 'image');
            break;
          case 'css':
            link.setAttribute('as', 'style');
            break;
          case 'js':
            link.setAttribute('as', 'script');
            break;
          case 'woff':
          case 'woff2':
          case 'ttf':
          case 'otf':
            link.setAttribute('as', 'font');
            break;
        }
      }
      
      document.head.appendChild(link);
    });
  }
  
  /**
   * 资源加载成功处理
   * @param {Object} resource - 资源对象
   */
  resourceLoaded(resource) {
    if (!resource || !resource.key) return;
    
    // 更新状态
    resource.status = 'loaded';
    
    // 添加到已加载集合
    this.loadedResources.add(resource.key);
    
    // 从队列中移除
    this.resourceQueue = this.resourceQueue.filter(item => item.key !== resource.key);
    
    // 触发加载事件
    this.triggerEvent('resourceLoaded', resource);
  }
  
  /**
   * 资源加载失败处理
   * @param {Object} resource - 资源对象
   * @param {Error} error - 错误对象
   */
  resourceFailed(resource, error) {
    if (!resource) return;
    
    // 更新状态
    resource.status = 'failed';
    resource.error = error;
    
    // 触发错误事件
    this.triggerEvent('resourceFailed', resource);
    
    console.error(`[资源加载器] 加载失败: ${resource.src}`, error);
  }
  
  /**
   * 加载延迟资源
   */
  loadDeferredResources() {
    // 加载队列中剩余的资源
    const remainingResources = this.resourceQueue.filter(
      resource => resource.status === 'queued'
    );
    
    remainingResources.forEach(resource => {
      this.loadResource(resource);
    });
  }
  
  /**
   * 触发事件
   * @param {String} eventName - 事件名称
   * @param {Object} data - 事件数据
   */
  triggerEvent(eventName, data) {
    const event = new CustomEvent(`resourceLoader:${eventName}`, { detail: data });
    window.dispatchEvent(event);
  }
}

// 创建默认实例
const resourceLoader = new ResourceLoader();

// 导出
export default resourceLoader;
export { ResourceLoader };